package pl.poznan.put.cs.to.tsp.heuristics;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Random;

import pl.poznan.put.cs.to.tsp.common.IResultHolder;
import pl.poznan.put.cs.to.tsp.common.Vertexes;
import pl.poznan.put.cs.to.tsp.listeners.TSPListener;

public class RandomHeuristic implements IResultHolder {
	private Vertexes vertexes;
	private Random random;
	private TSPListener tspListener;
	private LinkedList<Integer> listA = new LinkedList<Integer>();
	private LinkedList<Integer> listB = new LinkedList<Integer>();

	public RandomHeuristic(Vertexes vertexes, TSPListener tspListener) {
		this.vertexes = vertexes;
		this.random = new Random();
		this.tspListener = tspListener;
		this.generateResult();
	}

	private void generateResult() {
		int numberOfVertexes = this.vertexes.getNumberOfNodes();
		int selectedVertexNo;
		int selectedVertexID;
		ArrayList<Integer> freeVertexes = new ArrayList<Integer>();
		for (int i = 0; i < numberOfVertexes; i++) {
			freeVertexes.add(i);
		}
		while (!freeVertexes.isEmpty()) {
			selectedVertexNo = this.random.nextInt(freeVertexes.size());
			selectedVertexID = freeVertexes.remove(selectedVertexNo);
			if (this.random.nextBoolean()) {
				listA.add(selectedVertexID);
			} else {
				listB.add(selectedVertexID);
			}
		}
		this.tspListener.solutionGenerated(listA, listB, vertexes);
	}

	private final void printResult(LinkedList<Integer> res) {
		for (Integer i : res) {
			System.out.print(i + " -> ");
		}
		System.out.println();
	}

	public void printResults() {
		System.out.println("A: " + this.getLengthA());
		this.printResult(listA);
		System.out.println("B: " + this.getLengthB());
		this.printResult(listB);
	}

	@Override
	public int getLengthA() {
		return calculateLength(this.listA);
	}

	@Override
	public int getLengthB() {
		return calculateLength(this.listB);
	}

	private int calculateLength(LinkedList<Integer> res) {
		int distance = 0;
		int first = res.getFirst();
		int last = res.getLast();
		int before = -1;

		for (Integer i : res) {
			if (before == -1) {
				distance += vertexes.getDistanceBetween(first, last);
			} else {
				distance += vertexes.getDistanceBetween(before, i);
			}
			before = i;
		}

		return distance;
	}

	@Override
	public LinkedList<Integer> getListA() {
		return this.listA;
	}

	@Override
	public LinkedList<Integer> getListB() {
		return this.listB;
	}

	@Override
	public Vertexes getVertexes() {
		return vertexes;
	}

	@Override
	public int compareTo(IResultHolder o) {
		int local = this.getLengthA() + this.getLengthB();
		int other = o.getLengthA() + o.getLengthB();
		return local - other;
	}
}
